package com.lyf.auth.controller;

import com.lyf.auth.constant.ResponseCodeEnum;
import com.lyf.auth.domain.pojo.AuthConfiguration;
import com.lyf.auth.domain.pojo.ScopeSupportApiListAccess;
import com.lyf.auth.domain.request.*;
import com.lyf.auth.domain.response.GetJWKsResponseBody;
import com.lyf.auth.domain.response.LoginResponseBody;
import com.lyf.auth.domain.settings.WhiteListSettings;
import com.lyf.auth.service.AuthProviderService;
import com.lyf.auth.service.EncryptService;
import com.lyf.auth.utils.TimeUtil;
import com.lyf.auth.utils.Utils;
import com.lyf.common.api.CommonResult;
import com.lyf.common.api.ResultCode;
import com.lyf.common.utils.JacksonUtil;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jwts;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.security.interfaces.RSAPublicKey;
import java.util.Base64;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import static com.lyf.auth.constant.ResponseCodeEnum.RESPONSE_CODE_TOKEN_TIME_EXPIRED;
import static com.lyf.common.api.ResultCode.*;
import static com.lyf.common.constant.Constant.*;

@RestController
@RequestMapping("/cvp/oauth2")
@Api(tags = {"认证平台接口"})
public class AuthProviderController {
    private static final Logger logger = LoggerFactory.getLogger(AuthProviderController.class);
    @Autowired
    private AuthProviderService authProviderService;
    @Autowired
    private EncryptService encryptService;
    @Autowired
    private WhiteListSettings whiteListSettings;
    @Autowired
    private Utils utils;

    @ApiOperation("获取token")
    @PostMapping(value = "/token")
    public CommonResult generateToken(@RequestHeader("Authorization") String authorization, @RequestParam(name = "grant_type") String grantType, @RequestParam(name = "scope") String scope) {
        LoginRequestBody loginRequestBody = new LoginRequestBody();
        loginRequestBody.setGrantType(grantType);
        loginRequestBody.setScope(scope);
        LoginResponseBody loginResponseBody = new LoginResponseBody();
        if (!authorization.contains(BASIC_AUTH_START)) {
            logger.info("authorization not contains Basic");
            return CommonResult.failed(AUTHORIZATION_NOT_ACCEPT, "authorization not contains Basic");
        } else {
            authorization = authorization.replace(BASIC_AUTH_START, "");
            String clientIdAndClientSecret = "";

            try {
                byte[] bytes = Base64.getDecoder().decode(authorization);
                clientIdAndClientSecret = new String(bytes, "utf-8");
            } catch (Exception var17) {
                logger.info("authorization not base64");
                return CommonResult.failed(AUTHORIZATION_NOT_ACCEPT, "authorization not base64");
            }
            String[] strings = clientIdAndClientSecret.split(":");
            if (strings.length < 2) {
                logger.info("authorization must have client_id and client_secret:decoded authorization={}", clientIdAndClientSecret);
                return CommonResult.failed(AUTHORIZATION_NOT_ACCEPT, "authorization must have client_id and client_secret");
            } else if (!GRANT_TYPE.equals(loginRequestBody.getGrantType())) {
                return CommonResult.failed(AUTHORIZATION_NOT_ACCEPT, "only support grant_type:client_credentials");
            } else {
                String clientId = strings[0];
                String clientSecret = strings[1];
                AuthConfiguration clientInfo = authProviderService.getClientInfo(clientId);
                if (clientInfo != null && clientSecret.equals(clientInfo.getClientSecret())) {
                    logger.info("参数打印{}，{}", clientInfo.getScopes(), loginRequestBody.getScope());
                    Set<String> scopes = clientInfo.getScopes();
                    if(scopes.contains(loginRequestBody.getScope())){
                        try {
                            loginRequestBody.setClientId(clientId);
                            loginResponseBody = authProviderService.generateJWTToken(loginRequestBody);
                            return CommonResult.success(loginResponseBody);
                        } catch (Exception var16) {
                            logger.info("generateJWTToken error:" + var16.getMessage());
                            return CommonResult.failed(ResultCode.FAILED, "generateJWTToken error");
                        }
                    }

                    logger.error("permission error: client_id:{} scope:{}, cur_support_scope_list:{}", new Object[]{clientId, scope, clientInfo.getScopes()});
                    return CommonResult.failed(AUTHORIZATION_NOT_ACCEPT, "This client does not have permission to use scope");

                } else {
                    logger.info("authorization have invalid client_id or client_secret:parse header get clientId={}, clientSecret={}", clientId, clientSecret);
                    return CommonResult.failed(AUTHORIZATION_NOT_ACCEPT, "authorization have invalid client_id or client_secret");
                }
            }
        }
    }
    @ApiOperation("校验token")
    @PostMapping(value = "/check_token")
    public CommonResult checkToken(@RequestHeader("Authorization") String authorization, @Valid @RequestBody CheckTokenRequestBody checkTokenRequestBody, HttpServletResponse httpServletResponse) throws Exception {
        logger.info("http header:[authorization={}],body:[{}]", authorization, JacksonUtil.object2Json(checkTokenRequestBody));
        if (!authorization.contains(BEARER_AUTH_START)) {
            return CommonResult.failed(BAD_REQUEST, "authorization not contains Bearer");
        } else {
            String token = authorization.replace(BEARER_AUTH_START, "");
            if (!checkTokenRequestBody.getGrantType().equals(GRANT_TYPE)) {
                return CommonResult.failed(BAD_REQUEST, "only support grant_type:client_credentials");
            }
            return authProviderService.checkToken(checkTokenRequestBody.getUrl(), token);
        }
    }
    @ApiOperation("获取公钥信息")
    @GetMapping(value = "/get_jwks")
    public CommonResult getJWKs() {
        GetJWKsResponseBody getJWKsResponseBody = new GetJWKsResponseBody();

        try {
            getJWKsResponseBody = encryptService.getJWKs();
        } catch (Exception var5) {
            logger.info(var5.getMessage());
            getJWKsResponseBody.setMessage("system error");
            return CommonResult.failed(FAILED, getJWKsResponseBody);
        }

        return CommonResult.success(getJWKsResponseBody);
    }
    @ApiOperation("接口绑定scope")
    @PostMapping("/bindScopeApi")
    public CommonResult addScope(@RequestHeader("Authorization") String authorization, @Valid @RequestBody AddScopeRequestBody addScopeRequestBody) {
        logger.info("http header:[authorization={}],body:[{}]", authorization, addScopeRequestBody);
        try {
            if (!authorization.contains(BEARER_AUTH_START)) {
                throw new RuntimeException("authorization not contains Bearer");
            }

            String token = authorization.replace(BEARER_AUTH_START, "");
            RSAPublicKey rsaPublicKey = encryptService.loadPublicKeyFromConf();
            Claims claims = (Claims) Jwts.parser().setSigningKey(rsaPublicKey).parseClaimsJws(token).getBody();
            Long nowTime = TimeUtil.getNowTimeSeconds();
            Integer exp = (Integer) claims.get("exp");
            Integer iat = (Integer) claims.get("iat");
            if (nowTime > (long) exp || nowTime < (long) iat) {
                logger.info("token expire or not effect");
                throw new RuntimeException("token expire or not effect");
            }

            String scope = (String) claims.get("scope");
            if (!scope.equals(ADMIN_SCOPE)) {
                return CommonResult.failed(UNAUTHORIZED_INVALID_AUTHORIZATION,"scope not equals add_scope apiId");
            }

            authProviderService.addScope(addScopeRequestBody);
            return CommonResult.success(true);
        } catch (ExpiredJwtException var13) {
            logger.error("token is expired:" + var13.getMessage());
            return CommonResult.failed(RESPONSE_CODE_TOKEN_TIME_EXPIRED);
        } catch (Exception var14) {
            logger.error("addScope error:" + var14.getMessage());
            return CommonResult.failed("addScope error");
        }


    }
    @ApiOperation("注册client")
    @PostMapping("/register")
    public CommonResult registerAuthService(@RequestHeader("Authorization") String authorization, @RequestBody RegisterRequestBody registerRequestBody) {
        CommonResult commResponse = new CommonResult<>();
        try {
            if (!authorization.contains(BEARER_AUTH_START)) {
                throw new RuntimeException("authorization not contains Bearer");
            }

            String token = authorization.replace(BEARER_AUTH_START, "");
            RSAPublicKey rsaPublicKey = encryptService.loadPublicKeyFromConf();
            Claims claims = (Claims) Jwts.parser().setSigningKey(rsaPublicKey).parseClaimsJws(token).getBody();
            Long nowTime = TimeUtil.getNowTimeSeconds();
            Integer exp = (Integer) claims.get("exp");
            Integer iat = (Integer) claims.get("iat");
            if (nowTime > (long) exp || nowTime < (long) iat) {
                logger.info("token expire or not effect");
                throw new RuntimeException("token expire or not effect");
            }

            String scope = (String) claims.get("scope");
            if (!scope.equals(ADMIN_SCOPE)) {
                throw new RuntimeException("scope not equals add_scope apiId");
            }

            AuthConfiguration authConfiguration = authProviderService.registerAuthService(registerRequestBody.getComment(), registerRequestBody.getOwner());
            commResponse.setCode(ResponseCodeEnum.RESPONSE_CODE_SUCCESS.getCode());
            commResponse.setData(authConfiguration);
        } catch (ExpiredJwtException var12) {
            logger.info("token is expired:" + var12.getMessage());
            commResponse.setMsg("token expire");
            commResponse.setCode(RESPONSE_CODE_TOKEN_TIME_EXPIRED.getCode());
        } catch (Exception var13) {
            logger.info("register client info error:{}", var13.getMessage());
            commResponse.setCode(ResponseCodeEnum.RESPONSE_CODE_ERROR.getCode());
            commResponse.setMsg("error");
        }

        return commResponse;
    }
    @ApiOperation("新增scope")
    @PostMapping(value = "/client/add_scope")
    public CommonResult addClientScope(@RequestHeader("Authorization") String authorization, @RequestBody AddClientScopeRequestBody request) {

        try {
            if (!authorization.contains(BEARER_AUTH_START)) {
                throw new RuntimeException("authorization not contains Bearer");
            }

            String token = authorization.replace(BEARER_AUTH_START, "");
            RSAPublicKey rsaPublicKey = encryptService.loadPublicKeyFromConf();
            Claims claims = (Claims) Jwts.parser().setSigningKey(rsaPublicKey).parseClaimsJws(token).getBody();
            Long nowTime = TimeUtil.getNowTimeSeconds();
            Integer exp = (Integer) claims.get("exp");
            Integer iat = (Integer) claims.get("iat");
            if (nowTime > (long) exp || nowTime < (long) iat) {
                logger.info("token expire or not effect");
                throw new RuntimeException("token expire or not effect");
            }

            String scope = (String) claims.get("scope");
            if (!scope.equals(ADMIN_SCOPE)) {
                throw new RuntimeException("scope is not admin");
            }

            AuthConfiguration response = authProviderService.addClientScope(request);
            response.setClientSecret((String) null);
            return CommonResult.success(response);
        } catch (Exception var13) {
            logger.error("ex:{}", var13);
            return CommonResult.failed(ResponseCodeEnum.SYSTEM_ERROR);
        }

    }
    @ApiOperation("设置scope")
    @PostMapping(value = "/client/set_scope")
    public CommonResult setClientScope(@RequestHeader("Authorization") String authorization, @RequestBody AddClientScopeRequestBody request) {
        try {
            if (!authorization.contains(BEARER_AUTH_START)) {
                throw new RuntimeException("authorization not contains Bearer");
            }

            String token = authorization.replace(BEARER_AUTH_START, "");
            RSAPublicKey rsaPublicKey = encryptService.loadPublicKeyFromConf();
            Claims claims = (Claims) Jwts.parser().setSigningKey(rsaPublicKey).parseClaimsJws(token).getBody();
            Long nowTime = TimeUtil.getNowTimeSeconds();
            Integer exp = (Integer) claims.get("exp");
            Integer iat = (Integer) claims.get("iat");
            if (nowTime > (long) exp || nowTime < (long) iat) {
                logger.info("token expire or not effect");
                throw new RuntimeException("token expire or not effect");
            }

            String scope = (String) claims.get("scope");
            if (!scope.equals(ADMIN_SCOPE)) {
                throw new RuntimeException("scope is not admin");
            }

            AuthConfiguration response = authProviderService.setClientScope(request);
            response.setClientSecret((String) null);
            return CommonResult.success(response);
        } catch (Exception var13) {
            logger.error("ex:{}", var13);
            return CommonResult.failed(ResponseCodeEnum.SYSTEM_ERROR);
        }

    }
    @ApiOperation("client信息")
    @GetMapping("/client/info")
    public CommonResult getClientInfo(@RequestHeader("Authorization") String authorization, @RequestHeader("clientId") String clientId) throws Exception {
        try {
            if (!authorization.contains(BEARER_AUTH_START)) {
                throw new RuntimeException("authorization not contains Bearer");
            }

            String token = authorization.replace(BEARER_AUTH_START, "");
            RSAPublicKey rsaPublicKey = encryptService.loadPublicKeyFromConf();
            Claims claims = (Claims) Jwts.parser().setSigningKey(rsaPublicKey).parseClaimsJws(token).getBody();
            Long nowTime = TimeUtil.getNowTimeSeconds();
            Integer exp = (Integer) claims.get("exp");
            Integer iat = (Integer) claims.get("iat");
            if (nowTime > (long) exp || nowTime < (long) iat) {
                logger.info("token expire or not effect");
                throw new RuntimeException("token expire or not effect");
            }

            String scope = (String) claims.get("scope");
            if (!scope.equals(ADMIN_SCOPE)) {
                throw new RuntimeException("scope is not admin");
            }

            AuthConfiguration response = authProviderService.getClientInfo(clientId);
            if (response != null) {
                response.setClientSecret((String) null);
                return CommonResult.success(response);
            }
            return CommonResult.failed(ResponseCodeEnum.RESPONSE_CODE_INVALID_PARAMETER);
        } catch (Exception var13) {
            logger.error("ex:{}", var13);
            return CommonResult.failed(ResponseCodeEnum.SYSTEM_ERROR);
        }

    }
    @ApiOperation("scope信息")
    @GetMapping(value = "/scope/info")
    public CommonResult getScopeInfo(@RequestHeader("Authorization") String authorization) {
        try {
            if (!authorization.contains(BEARER_AUTH_START)) {
                throw new RuntimeException("authorization not contains Bearer");
            }

            String token = authorization.replace(BEARER_AUTH_START, "");
            RSAPublicKey rsaPublicKey = encryptService.loadPublicKeyFromConf();
            Claims claims = (Claims) Jwts.parser().setSigningKey(rsaPublicKey).parseClaimsJws(token).getBody();
            Long nowTime = TimeUtil.getNowTimeSeconds();
            Integer exp = (Integer) claims.get("exp");
            Integer iat = (Integer) claims.get("iat");
            if (nowTime > (long) exp || nowTime < (long) iat) {
                logger.info("token expire or not effect");
                throw new RuntimeException("token expire or not effect");
            }

            String scope = (String) claims.get("scope");
            if (!scope.equals(ADMIN_SCOPE)) {
                throw new RuntimeException("scope is not admin");
            }
            List<ScopeSupportApiListAccess> scopeInfoAccessArrayList = authProviderService.getAllScopeInfo();
            return CommonResult.success(scopeInfoAccessArrayList);
        } catch (Exception var13) {
            logger.error("ex:{}", var13);
            return CommonResult.failed(ResponseCodeEnum.SYSTEM_ERROR);
        }

    }
    @ApiOperation("添加公钥信息")
    @PostMapping("/add_jwk")
    public CommonResult addJwk(@RequestBody AddJwkRequestBody addJwkRequestBody) {
        encryptService.addJwk(addJwkRequestBody.getPublicKey());
        return CommonResult.success(true);
    }
}
